
import { UserAPI } from "@/api/UserAPI";
import { useUserStore } from "@/stores/userStore";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
import axios, { AxiosError } from "axios";
import { ElMessage } from "element-plus";
import router from "../router";

interface BkAxiosInstance extends AxiosInstance {
  request<T = any, D = any>(config: AxiosRequestConfig<D>): Promise<T>;
}

export default class BkRequestManager {
  // 既然要实现单例模式, 当前类的实例就不能被外部创建
  // 存储单例对象
  private static _singletonInstance: BkRequestManager;
  // 用于保存 axios 实例对象
  private readonly _intance: BkAxiosInstance;
  // 用于保存 useStore 实例
  private _userStore = useUserStore();
  // 接口请求地址
  public static baseURL = '/api';
  // 将构造函数设置为私有 防止外部直接实例化当前类来创建实例
  private constructor() {
    // 创建新的 axios 实例 专门用于和服务器端进行请求交互
    this._intance = axios.create({ baseURL: BkRequestManager.baseURL });
    // 注册请求拦截器
    this._intance.interceptors.request.use(
      // 在请求头中加入token
      this._addTokenToRequestHeader.bind(this)
    );
    // 注册响应拦截器
    this._intance.interceptors.response.use(
      // 响应的成功态, 剥离响应对象
      this._peelOffAxiosResponse,
      // 响应的失败态, 处理未授权的情况
      this._unauthorized.bind(this)
    );
  }
  // 用于获取单例对象的
  static get instance() {
    // 判断单例对象是否存在
    if (typeof BkRequestManager._singletonInstance === "undefined") {
      // 如果不存在 创建该对象
      BkRequestManager._singletonInstance = new BkRequestManager();
    }
    // 返回单例对象
    return BkRequestManager._singletonInstance;
  }
  // 在请求头中加入token
  private _addTokenToRequestHeader(config: AxiosRequestConfig) {
    // 我们期望该方法中的 this 关键字指向当前类的实例
    const token = this._userStore.userinfo.result.token;
    // 如果 token 存在 将 token 加入到请求头中
    if (token) config.headers = { Authorization: `Bearer ${token}` };
    // 返回 config 否则报错
    return config;
  }
  // 剥离响应对象 直接为调用者返回服务器端的数据
  private _peelOffAxiosResponse(response: AxiosResponse) {
    return response.data;
  }
  // 统一的错误处理 (未授权)
 private _unauthorized(error: unknown) {

    // 检测 error 参数是否为 axios 封装的 error 对象
    if (error instanceof AxiosError) {      
      // 401 表示未授权
      if (error.response?.status === 401) {
        // 清空本地用户信息
        this._userStore.$reset();
        ElMessage({
          showClose: true,
          message: error.response.data,
          type: "error",
        });
        // 跳转到登录页面
        router.replace(`/login?return=${encodeURIComponent(router.currentRoute.value.fullPath)}`);
      }
    } 
    //服务端=>统一错误处理=>开发者错误处理
    //抛出错误不然拿不到
    return Promise.reject(error)
  }
  // 添加一个外部用于发送请求的方法
  public request<T = any, D = any>(config: AxiosRequestConfig<D>): Promise<T> {
    // 由于我们调用的是 axios 实例下的 request 方法, 这个方法他的参数被要求是 AxiosRequestConfig leixing
    return this._intance.request<T, D>(config);
  }
}